/*
Copyright 2010 Iain Surgey.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#__body__

/*
==============
D_SolidSurf

Normal surface cached, texture mapped surface
==============
*/
private inline function D_SolidSurf (s : Int)
{
	#{s| surf_t *s}
	#{d| float mipval}
	d_zistepu = #{s->d_zistepu};
	d_zistepv = #{s->d_zistepv};
	d_ziorigin = #{s->d_ziorigin};
	
	pface = #{s->msurf};
	cachewidth = #{pface->texinfo->image->width};
	cacheheight = #{pface->texinfo->image->height};
	
	cw16 = cachewidth << 16;
	ch16 = cacheheight << 16;
	
	r_lightptr = #{pface->samples};
	r_lightwidth = (#{pface->extents[0]}>>4)+1;
	
	mipval = #{s->nearzi} * #{pface->texinfo->mipadjust};
	
	if (mipval >= d_scalemip0 ) {
		cacheblock = #{pface->texinfo->image->pixels[0]};
		mshift = 16;
		cwid = cachewidth;
	} else if (mipval >= d_scalemip1 ) {
		cacheblock = #{pface->texinfo->image->pixels[1]};
		mshift = 17;
		cwid = cachewidth>>1;
	} else if (mipval >= d_scalemip2 ) {
		cacheblock = #{pface->texinfo->image->pixels[2]};
		mshift = 18;
		cwid = cachewidth>>2;
	} else {
		cacheblock = #{pface->texinfo->image->pixels[3]};
		mshift = 19;
		cwid = cachewidth>>3;
	}
	
	D_CalcGradients (s);
	
	if (!alias_visible) D_DrawSpans16 (#{s->spans});
	else D_DrawSpans16_alias (#{s->spans});
}


/*
==============
D_SkySurf
==============
*/
private function D_SkySurf (s : Int)
{
	#{s| surf_t *s}
	
	pface = #{s->msurf};
	cacheblock = #{pface->texinfo->image->pixels[0]};
	cachewidth = 256;
	cacheheight = 256;

	d_zistepu = #{s->d_zistepu};
	d_zistepv = #{s->d_zistepv};
	d_ziorigin = #{s->d_ziorigin};
	
	D_CalcSkyGradients (s);
	if (!alias_visible) D_DrawSkySpans16 (#{s->spans});
	else D_DrawSkySpans16_alias (#{s->spans});
}


/*
==============
D_CalcGradients
==============
*/
private inline function D_CalcGradients (fa : Int)
{
	#{d| mplane_t *pplane}
	#{d| float mipscale, t}
	#{d| int tvecs, sch, tch, smin, tmin}
	
	pplane = #{pface->plane};
	tvecs = #{pface->texinfo};
	
	mipscale = 4.0;
	
	TransformVector (tvecs, #{DCG_p_saxis});
	TransformVector (tvecs+16, #{DCG_p_taxis});
	
	t = xscaleinv * mipscale;
	d_sdivzstepu = #{DCG_p_saxis[0]} * t;
	d_tdivzstepu = #{DCG_p_taxis[0]} * t;
	
	t = yscaleinv * mipscale;
	d_sdivzstepv = -#{DCG_p_saxis[1]} * t;
	d_tdivzstepv = -#{DCG_p_taxis[1]} * t;
	
	d_sdivzorigin = #{DCG_p_saxis[2]} * mipscale - xcenter * d_sdivzstepu - ycenter * d_sdivzstepv;
	d_tdivzorigin = #{DCG_p_taxis[2]} * mipscale - xcenter * d_tdivzstepu - ycenter * d_tdivzstepv;
	
	smin = (#{pface->texturemins[0]}<<2);
	sch = ((smin + (cachewidth << 16)) % cachewidth);
	tmin = (#{pface->texturemins[1]}<<2);
	tch = ((tmin + (cacheheight << 16)) % cacheheight);
	
	VectorScale (#{transformed_modelorg}, mipscale, #{DCG_p_temp1});
	
	t = 0x10000 * mipscale;
	sadjust = (Std.int(DotProduct (#{DCG_p_temp1}, #{DCG_p_saxis}) * 0x10000 + 0.5))
	+ sch + Std.int(Memory.getFloat( tvecs+12 )*t);
	tadjust = (Std.int(DotProduct (#{DCG_p_temp1}, #{DCG_p_taxis}) * 0x10000 + 0.5))
	+ tch + Std.int(Memory.getFloat( tvecs+28 )*t);
	
	sadjustl = sadjust - sch - (smin<<16);
	tadjustl = tadjust - tch - (tmin<<16);
}

private function D_CalcSkyGradients (fa : Int)
{
	#{d| mplane_t *pplane}
	#{d| int tvecs}
	
	pplane = #{pface->plane};
	tvecs = #{pface->texinfo};
	
	TransformVector (tvecs, #{DCG_p_saxis});
	TransformVector (tvecs+16, #{DCG_p_taxis});
	
	d_sdivzstepu = #{DCG_p_saxis[0]} * xscaleinv;
	d_tdivzstepu = #{DCG_p_taxis[0]} * xscaleinv;
	
	d_sdivzstepv = -#{DCG_p_saxis[1]} * yscaleinv;
	d_tdivzstepv = -#{DCG_p_taxis[1]} * yscaleinv;
	
	d_sdivzorigin = #{DCG_p_saxis[2]} - xcenter * d_sdivzstepu - ycenter * d_sdivzstepv;
	d_tdivzorigin = #{DCG_p_taxis[2]} - xcenter * d_tdivzstepu - ycenter * d_tdivzstepv;
	
	sadjust = ((Std.int(DotProduct (#{transformed_modelorg}, #{DCG_p_saxis}) * 0x10000 - 0.5))
	 -	((#{pface->texturemins[0]} << 16))
	+ Std.int(Memory.getFloat( tvecs+12 )*0x10000));
			
	tadjust = ((Std.int(DotProduct (#{transformed_modelorg}, #{DCG_p_taxis}) * 0x10000 - 0.5)) 
	- ((#{pface->texturemins[1]} << 16))
	+ Std.int(Memory.getFloat( tvecs+28 )*0x10000));
}


/*
=============
D_DrawSpans16
=============
*/
private inline function D_DrawSpans16_alias (pspan : Int)
{
	#{s| espan_t *pspan}
	#{d| int				count, spancount,pdest,srcptr,spancount2}
	#{d| int		s, t, snext, tnext, sstep, tstep, slight, tlight}
	#{d| float			sdivz, tdivz, zi, z, du, dv, spancountminus1}
	#{d| float			sdivz8stepu, tdivz8stepu, zi8stepu}
	
	#{d| int _pu, _pv, _tmp}
	#{d| int lval,lstep,lmas}
	
	#{d| int zmin, zmax}
	#{d| int izi, izistep}
	#{d| int pzsrc, skip}
	
	sstep = 0;	// keep compiler happy
	tstep = 0;	// ditto
	
	sdivz8stepu = d_sdivzstepu * SPANDIV;
	tdivz8stepu = d_tdivzstepu * SPANDIV;
	zi8stepu = d_zistepu * SPANDIV;
	izistep = Std.int(d_zistepu * 0x8000 * 0x10000);
	
	lval = 0x1A00;
	
	var checkz : Bool;
	
	do
	{
		_pu = #{pspan->u};
		_pv = #{pspan->v};
		pdest = (RESH * _pv) + _pu;
		pzsrc = #{zbuffer} + (pdest<<1);
		pdest = DRAWOFS1 + (pdest<<2);
		
		du = _pu;
		dv = _pv;
		
		count = #{pspan->count};
		skip = 0;
		checkz = false;
		
		_tmp = Memory.getI32(#{zminmaxs}+(_pv<<2));
		if (_tmp & 0x7FC00000 == r_zmmframe) {
			zmin = (_tmp & 0x3FF800)>>11;
			zmax = (_tmp & 0x7FF);
			
			if (_pu < zmin) {
				if (_pu+count < zmin) {
					skip = count;
				} else {
					if (_pu+count < zmin) {
						skip = count;
					} else {
						skip = (zmin-_pu);
					}
				}
			} else {
				if (_pu < zmax) {
					checkz = true;
					if (_pu+count < zmax) {
						skip = count;
					} else {
						skip = (zmax-_pu);
					}
				} else {
					skip = count;
				}
			}
			
		} else {
			zmin = 2047;
			zmax = 0;
			skip = count;
		}
		
		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
		//izi = Std.int(zi * 0x8000 * 0x10000);
		
		z = 0x10000 / zi;
		s = Std.int(sdivz * z) + sadjust;
		t = Std.int(tdivz * z) + tadjust;
		
		//*
		while (s > cw16) { s -= cw16; sadjust -= cw16;}
		while (s < 0) { s += cw16; sadjust += cw16; }
		while (t > ch16) { t -= ch16; tadjust -= ch16; }
		while (t < 0) { t += ch16; tadjust += ch16; }//*/
		
		slight = s + (sadjustl - sadjust);
		tlight = t + (tadjustl - tadjust);
		_pv = Memory.getByte(r_lightptr + (slight>>22) + ((tlight>>22)*r_lightwidth))<<10;
		
		do {
			if (checkz) { izi = Std.int(zi * 0x8000 * 0x10000); }
			else { izi = 0; pzsrc += (skip<<1); }
			_pu += skip;
			count -= skip;
			
			while (skip > 0) {
				// calculate s and t at the far end of the span
				if (skip >= SPANDIV)
					spancount = SPANDIV;
				else
					spancount = skip;

				skip -= spancount;

				if (skip > 0)
				{
					sdivz += sdivz8stepu;
					tdivz += tdivz8stepu;
					zi += zi8stepu;
					z = 0x10000 / zi;	// prescale to 16.16 fixed-point
					
					snext = Std.int(sdivz * z) + sadjust;
					tnext = Std.int(tdivz * z) + tadjust;
					
					sstep = (snext - s) >> SPANDIV_SHIFT;
					tstep = (tnext - t) >> SPANDIV_SHIFT;
				}
				else
				{
					spancountminus1 = (spancount - 1);
					sdivz += d_sdivzstepu * spancountminus1;
					tdivz += d_tdivzstepu * spancountminus1;
					zi += d_zistepu * spancountminus1;
					z = 0x10000 / zi;	// prescale to 16.16 fixed-point
					
					snext = Std.int(sdivz * z) + sadjust;
					tnext = Std.int(tdivz * z) + tadjust;

					if (spancount > 1)
					{
						sstep = Std.int((snext - s) / spancountminus1);
						tstep = Std.int((tnext - t) / spancountminus1);
					}
				}
				
				slight = snext + (sadjustl - sadjust);
				tlight = tnext + (tadjustl - tadjust);
				lval = _pv;
				_pv = Memory.getByte(r_lightptr + (slight>>22) + ((tlight>>22)*r_lightwidth))<<10;
				lstep = (_pv-lval)>>SPANDIV_SHIFT;
				
				if (checkz) {
					if (snext > cw16 || snext < 0 || tnext > cw16 || tnext < 0) {
						do
						{				
							if (s > cw16) { s -= cw16; sadjust -= cw16; snext -= cw16; } 
							else if (s < 0) { s += cw16; sadjust += cw16; snext += cw16; }
							if (t > ch16) { t -= ch16; tadjust -= ch16; tnext -= ch16; } 
							else if (t < 0) { t += ch16; tadjust += ch16; tnext += ch16; }
							srcptr = Memory.getUI16( cacheblock + (((s >> mshift) + (t >> mshift) * cwid )<<1) );
							lmas = lval&0x3FC00;
							
							if (Memory.getUI16(pzsrc) < (izi>>16)) {
								//*
								_tmp = Memory.getUI16( (lmas+(srcptr&0x3FF))<<1 );
								Memory.setByte(pdest++,(_tmp&0xFF));
								Memory.setByte(pdest++,Memory.getByte(DRAWOFS0+(srcptr&0xFC00)+(lmas>>10)));
								Memory.setByte(pdest++,(_tmp>>8));
								pdest++;//*/
							} else pdest += 4;
							
							s += sstep;
							t += tstep;
							lval += lstep;
							izi += izistep;
							pzsrc += 2;
						} while (--spancount > 0);
					} else {
						do
						{
							srcptr = Memory.getUI16( cacheblock + (((s >> mshift) + (t >> mshift) * cwid )<<1) );
							lmas = lval&0x3FC00;
							
							if (Memory.getUI16(pzsrc) < (izi>>16)) {
								//*
								_tmp = Memory.getUI16( (lmas+(srcptr&0x3FF))<<1 );
								Memory.setByte(pdest++,(_tmp&0xFF));
								Memory.setByte(pdest++,Memory.getByte(DRAWOFS0+(srcptr&0xFC00)+(lmas>>10)));
								Memory.setByte(pdest++,(_tmp>>8));
								pdest++;//*/
							} else pdest += 4;
							
							s += sstep;
							t += tstep;
							lval += lstep;
							izi += izistep;
							pzsrc += 2;
						} while (--spancount > 0);
					}
				} else {
					if (snext > cw16 || snext < 0 || tnext > cw16 || tnext < 0) {
						do
						{				
							if (s > cw16) { s -= cw16; sadjust -= cw16; snext -= cw16; } 
							else if (s < 0) { s += cw16; sadjust += cw16; snext += cw16; }
							if (t > ch16) { t -= ch16; tadjust -= ch16; tnext -= ch16; } 
							else if (t < 0) { t += ch16; tadjust += ch16; tnext += ch16; }
							srcptr = Memory.getUI16( cacheblock + (((s >> mshift) + (t >> mshift) * cwid )<<1) );
							lmas = lval&0x3FC00;
							
							//*
							_tmp = Memory.getUI16( (lmas+(srcptr&0x3FF))<<1 );
							Memory.setByte(pdest++,(_tmp&0xFF));
							Memory.setByte(pdest++,Memory.getByte(DRAWOFS0+(srcptr&0xFC00)+(lmas>>10)));
							Memory.setByte(pdest++,(_tmp>>8));
							pdest++;//*/
							
							s += sstep;
							t += tstep;
							lval += lstep;
						} while (--spancount > 0);
					} else {
						do
						{
							srcptr = Memory.getUI16( cacheblock + (((s >> mshift) + (t >> mshift) * cwid )<<1) );
							lmas = lval&0x3FC00;
							
							//*
							_tmp = Memory.getUI16( (lmas+(srcptr&0x3FF))<<1 );
							Memory.setByte(pdest++,(_tmp&0xFF));
							Memory.setByte(pdest++,Memory.getByte(DRAWOFS0+(srcptr&0xFC00)+(lmas>>10)));
							Memory.setByte(pdest++,(_tmp>>8));
							pdest++;//*/
							
							s += sstep;
							t += tstep;
							lval += lstep;
						} while (--spancount > 0);
					}
				}
					
				s = snext;
				t = tnext;
				
			}
			
			//break;
			
			if (count < 1) break;
			
			checkz = false;
			
			if (_pu < zmin) {
				if (_pu+count < zmin) {
					skip = count;
				} else {
					if (_pu+count < zmin) {
						skip = count;
					} else {
						skip = (zmin-_pu);
					}
				}
			} else {
				if (_pu < zmax) {
					checkz = true;
					if (_pu+count < zmax) {
						skip = count;
					} else {
						skip = (zmax-_pu);
					}
				} else {
					skip = count;
				}
			}
			
		} while (count > 0);
		
		pspan = #{pspan->pnext};
	} while (pspan > 4);
}



/*
=============
D_DrawSpans16
=============
*/
private inline function D_DrawSpans16 (pspan : Int)
{
	#{s| espan_t *pspan}
	#{d| int				count, spancount,pdest,srcptr,spancount2}
	#{d| int		s, t, snext, tnext, sstep, tstep, slight, tlight}
	#{d| float			sdivz, tdivz, zi, z, du, dv, spancountminus1}
	#{d| float			sdivz8stepu, tdivz8stepu, zi8stepu}
	
	#{d| int _pu, _pv}
	#{d| int lval,lstep,lmas}
	
	sstep = 0;	// keep compiler happy
	tstep = 0;	// ditto
	
	sdivz8stepu = d_sdivzstepu * SPANDIV;
	tdivz8stepu = d_tdivzstepu * SPANDIV;
	zi8stepu = d_zistepu * SPANDIV;
	
	lval = 0x1A00;
	
	do
	{
		_pu = #{pspan->u};
		_pv = #{pspan->v};
		pdest = DRAWOFS1+(((RESH * _pv) + _pu)<<2);
		
		du = _pu;
		dv = _pv;
		
		count = #{pspan->count};
		
		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
		
		z = 0x10000 / zi;
		s = Std.int(sdivz * z) + sadjust;
		t = Std.int(tdivz * z) + tadjust;
		
		//*
		while (s > cw16) { s -= cw16; sadjust -= cw16;}
		while (s < 0) { s += cw16; sadjust += cw16; }
		while (t > ch16) { t -= ch16; tadjust -= ch16; }
		while (t < 0) { t += ch16; tadjust += ch16; }//*/
		
		/*
		if (s > cw16) { _pu = s%cw16; sadjust -= (s-_pu); s = _pu; }
		else if (s < 0) { _pu = s%cw16; sadjust += ((-s)+_pu); s = _pu; }
		if (t > ch16) { _pu = t%ch16; tadjust -= (t-_pu); t = _pu; }
		else if (t < 0) { _pu = t%ch16; tadjust += ((-t)+_pu); t = _pu; }//*/
		
		slight = s + (sadjustl - sadjust);
		tlight = t + (tadjustl - tadjust);
		_pv = Memory.getByte(r_lightptr + (slight>>22) + ((tlight>>22)*r_lightwidth))<<10;
		
		do {
			// calculate s and t at the far end of the span
			if (count >= SPANDIV)
				spancount = SPANDIV;
			else
				spancount = count;

			count -= spancount;

			if (count > 0)
			{
				sdivz += sdivz8stepu;
				tdivz += tdivz8stepu;
				zi += zi8stepu;
				z = 0x10000 / zi;	// prescale to 16.16 fixed-point

				snext = Std.int(sdivz * z) + sadjust;
				tnext = Std.int(tdivz * z) + tadjust;
				
				sstep = (snext - s) >> SPANDIV_SHIFT;
				tstep = (tnext - t) >> SPANDIV_SHIFT;
			}
			else
			{
				spancountminus1 = (spancount - 1);
				sdivz += d_sdivzstepu * spancountminus1;
				tdivz += d_tdivzstepu * spancountminus1;
				zi += d_zistepu * spancountminus1;
				z = 0x10000 / zi;	// prescale to 16.16 fixed-point
				
				snext = Std.int(sdivz * z) + sadjust;
				tnext = Std.int(tdivz * z) + tadjust;

				if (spancount > 1)
				{
					sstep = Std.int((snext - s) / spancountminus1);
					tstep = Std.int((tnext - t) / spancountminus1);
				}
			}
			
			slight = snext + (sadjustl - sadjust);
			tlight = tnext + (tadjustl - tadjust);
			lval = _pv;
			_pv = Memory.getByte(r_lightptr + (slight>>22) + ((tlight>>22)*r_lightwidth))<<10;
			lstep = (_pv-lval)>>SPANDIV_SHIFT;
			
			if (snext > cw16 || snext < 0 || tnext > cw16 || tnext < 0) {
				do
				{				
					if (s > cw16) { s -= cw16; sadjust -= cw16; snext -= cw16; } 
					else if (s < 0) { s += cw16; sadjust += cw16; snext += cw16; }
					if (t > ch16) { t -= ch16; tadjust -= ch16; tnext -= ch16; } 
					else if (t < 0) { t += ch16; tadjust += ch16; tnext += ch16; }
					srcptr = Memory.getUI16( cacheblock + (((s >> mshift) + (t >> mshift) * cwid )<<1) );
					lmas = lval&0x3FC00;
					
					//*
					_pu = Memory.getUI16( (lmas+(srcptr&0x3FF))<<1 );
					Memory.setByte(pdest++,(_pu&0xFF));
					Memory.setByte(pdest++,Memory.getByte(DRAWOFS0+(srcptr&0xFC00)+(lmas>>10)));
					Memory.setByte(pdest++,(_pu>>8));
					pdest++;//*/
					
					s += sstep;
					t += tstep;
					lval += lstep;
				} while (--spancount > 0);
			} else {
				do
				{
					srcptr = Memory.getUI16( cacheblock + (((s >> mshift) + (t >> mshift) * cwid )<<1) );
					lmas = lval&0x3FC00;
					
					//*
					_pu = Memory.getUI16( (lmas+(srcptr&0x3FF))<<1 );
					Memory.setByte(pdest++,(_pu&0xFF));
					Memory.setByte(pdest++,Memory.getByte(DRAWOFS0+(srcptr&0xFC00)+(lmas>>10)));
					Memory.setByte(pdest++,(_pu>>8));
					pdest++;//*/
					
					s += sstep;
					t += tstep;
					lval += lstep;
				} while (--spancount > 0);
			}
				
			s = snext;
			t = tnext;
			
		} while(count > 0);
		
		pspan = #{pspan->pnext};
	} while (pspan > 4);
}


/*
=============
D_DrawSkySpans16
=============
*/
private function D_DrawSkySpans16_alias (pspan : Int)
{
	#{s| espan_t *pspan}
	#{d| int				count, spancount,pdest}
	#{d| int		s, t, snext, tnext, sstep, tstep}
	#{d| float			sdivz, tdivz, zi, z, du, dv, spancountminus1}
	#{d| float			sdivz8stepu, tdivz8stepu, zi8stepu}
	#{d| int zmin, zmax, _pu, _pv, zval}
	
	sstep = 0;	// keep compiler happy
	tstep = 0;	// ditto
	
	sdivz8stepu = d_sdivzstepu * SPANDIV;
	tdivz8stepu = d_tdivzstepu * SPANDIV;
	zi8stepu = d_zistepu * SPANDIV;

	do
	{
		_pu = #{pspan->u};
		_pv = #{pspan->v};
		pdest = DRAWOFS1+(((RESH * _pv) + _pu)<<2);

		count = #{pspan->count};
		spancount = 0;
		
		du = _pu;
		dv = _pv;
		
		zval = Memory.getI32(#{zminmaxs}+(_pv<<2));
		if (zval & 0x7FC00000 == r_zmmframe) {
			zmin = (zval & 0x3FF800)>>11;
			zmax = (zval & 0x7FF);
			
			if (_pu < zmin &&_pu+count < zmin)
				zmax = 0;
				
		} else {
			zmin = 2047;
			zmax = 0;
		}
		
	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
		z = 0x10000 / zi;	// prescale to 16.16 fixed-point

		s = Std.int(sdivz * z) + sadjust;
		t = Std.int(tdivz * z) + tadjust;
		
		do
		{
			
		// calculate s and t at the far end of the span
			if (count >= SPANDIV)
				spancount = SPANDIV;
			else
				spancount = count;

			count -= spancount;

			if (count > 0)
			{
				sdivz += sdivz8stepu;
				tdivz += tdivz8stepu;
				zi += zi8stepu;
				z = 0x10000 / zi;	// prescale to 16.16 fixed-point

				snext = Std.int(sdivz * z) + sadjust;
				tnext = Std.int(tdivz * z) + tadjust;

				sstep = (snext - s) >> SPANDIV_SHIFT;
				tstep = (tnext - t) >> SPANDIV_SHIFT;
			}
			else
			{
				spancountminus1 = (spancount - 1);
				sdivz += d_sdivzstepu * spancountminus1;
				tdivz += d_tdivzstepu * spancountminus1;
				zi += d_zistepu * spancountminus1;
				z = 0x10000 / zi;	// prescale to 16.16 fixed-point
				
				snext = Std.int(sdivz * z) + sadjust;
				tnext = Std.int(tdivz * z) + tadjust;

				if (spancount > 1)
				{
					sstep = Std.int((snext - s) / (spancountminus1));
					tstep = Std.int((tnext - t) / (spancountminus1));
				}
			}
			
			do
			{
				if (_pu > zmax || _pu < zmin || Memory.getI32(pdest+SCRBYTES) & 0xFFFF != r_zframe)
				Memory.setI32(pdest,Memory.getI32(cacheblock + (((s >> 16) + (t >> 16) * cachewidth )<<2)));
				
				s += sstep;
				t += tstep;
				
				pdest += 4;
			} while (--spancount > 0);

			s = snext;
			t = tnext;

		} while (count > 0);
		pspan = #{pspan->pnext};
	} while (pspan > 4);
}

/*
=============
D_DrawSkySpans16
=============
*/
private function D_DrawSkySpans16 (pspan : Int)
{
	#{s| espan_t *pspan}
	#{d| int				count, spancount,pdest}
	#{d| int		s, t, snext, tnext, sstep, tstep}
	#{d| float			sdivz, tdivz, zi, z, du, dv, spancountminus1}
	#{d| float			sdivz8stepu, tdivz8stepu, zi8stepu}
	#{d| int _pu, _pv}
	
	sstep = 0;	// keep compiler happy
	tstep = 0;	// ditto

	sdivz8stepu = d_sdivzstepu * SPANDIV;
	tdivz8stepu = d_tdivzstepu * SPANDIV;
	zi8stepu = d_zistepu * SPANDIV;

	do
	{
		_pu = #{pspan->u};
		_pv = #{pspan->v};
		pdest = DRAWOFS1+(((RESH * _pv) + _pu)<<2);

		count = #{pspan->count};
		spancount = 0;
		
		du = _pu;
		dv = _pv;
		
	// calculate the initial s/z, t/z, 1/z, s, and t and clamp
		sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
		tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
		zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
		z = 0x10000 / zi;	// prescale to 16.16 fixed-point

		s = Std.int(sdivz * z) + sadjust;
		t = Std.int(tdivz * z) + tadjust;
		
		do
		{
			
		// calculate s and t at the far end of the span
			if (count >= SPANDIV)
				spancount = SPANDIV;
			else
				spancount = count;

			count -= spancount;

			if (count > 0)
			{
				sdivz += sdivz8stepu;
				tdivz += tdivz8stepu;
				zi += zi8stepu;
				z = 0x10000 / zi;	// prescale to 16.16 fixed-point

				snext = Std.int(sdivz * z) + sadjust;
				tnext = Std.int(tdivz * z) + tadjust;

				sstep = (snext - s) >> SPANDIV_SHIFT;
				tstep = (tnext - t) >> SPANDIV_SHIFT;
			}
			else
			{
				spancountminus1 = (spancount - 1);
				sdivz += d_sdivzstepu * spancountminus1;
				tdivz += d_tdivzstepu * spancountminus1;
				zi += d_zistepu * spancountminus1;
				z = 0x10000 / zi;	// prescale to 16.16 fixed-point
				
				snext = Std.int(sdivz * z) + sadjust;
				tnext = Std.int(tdivz * z) + tadjust;

				if (spancount > 1)
				{
					sstep = Std.int((snext - s) / (spancountminus1));
					tstep = Std.int((tnext - t) / (spancountminus1));
				}
			}
			
			do
			{
				Memory.setI32(pdest,Memory.getI32(cacheblock + (((s >> 16) + (t >> 16) * cachewidth )<<2)));
				
				s += sstep;
				t += tstep;
				
				pdest += 4;
			} while (--spancount > 0);

			s = snext;
			t = tnext;

		} while (count > 0);
		pspan = #{pspan->pnext};
	} while (pspan > 4);
}
